use std::fmt::{Debug, Display};

use tokio::task::JoinError;
use zero2prod::{
    issue_delivery_worker::run_worker_until_stopped,
    telemetry::{get_subscriber, init_subscriber},
};

#[tokio::main]
async fn main() -> Result<(), std::io::Error> {
    init_subscriber(get_subscriber("zero2prod", "info", std::io::stdout));

    let configuration = zero2prod::get_configuration().expect("Faile to read configuration.");
    let app = zero2prod::startup::Application::build(&configuration)
        .await
        .expect("Failed to build application.");

    let app_task = tokio::spawn(app.run_until_stopped());
    let worker_task = tokio::spawn(run_worker_until_stopped(configuration));

    tokio::select! {
        o=app_task=>report_exit("API", o),
        o=worker_task=>report_exit("Background worker", o),
    };
    Ok(())
}

fn report_exit(task_name: &str, outcome: Result<Result<(), impl Debug + Display>, JoinError>) {
    match outcome {
        Ok(Ok(())) => {
            tracing::info!("{} has exited", task_name);
        }
        Ok(Err(e)) => {
            tracing::error!(error.cause_chain=?e,error.message=%e,"{} failed",task_name);
        }
        Err(e) => {
            tracing::error!(error.cause_chain=?e,error.message=%e,"{} task failed to complete",task_name);
        }
    }
}
